package com.ruoyi.extdata.aop;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.bizsys.domain.MonitorLog;
import com.ruoyi.bizsys.service.IMonitorLogService;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.FeishuUtils;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.extdata.component.MonnifyOrder;
import com.ruoyi.extdata.domain.OkRequestVo;
import com.ruoyi.extdata.domain.SmsData;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class ServiceDebugAspect {

    @Autowired
    RedisCache redisCache;

    @Autowired
    ISysConfigService iSysConfigService;

    //@Autowired
    //ISlackService iSlackService;

//    @Autowired
//    IFeishuService iFeishuService;

    @Autowired
    IMonitorLogService iMonitorLogService;

    @Autowired
    MonnifyOrder monnifyOrder;

    @Pointcut("execution(* com.ruoyi.extdata.service.impl.ExternalApiServiceImpl.*(..))" +
            " || execution(* com.ruoyi.extdata.service.impl.XdsServiceImpl.soapRequest(..))" +
            "")
    public void Pointcut() {
    }

    @AfterThrowing(pointcut = "Pointcut()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {

        if (ex instanceof BusinessException) {
            BusinessException be = (BusinessException) ex;
            log.error("{} - {}", be.getDetails(), be.getMessage());
        } else {
            log.error("三方接口异常：", ex);
        }

        String name = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());

        String isOpen = iSysConfigService.selectConfigByKey("ext_monitor_is_open");

        if (isOpen.equals("0")) {
            return;
        }

        Map<String, Object> data = getData(name, args);
        String apiName = data.get("apiName").toString();
        String param = data.get("param").toString();

        //是否属于网络异常
        if (StringUtils.containsAny(ex.toString(),
                RspEnmu.NETWORK_BUSY.getMessage(),
                RspEnmu.NETWORK_ERROR.getMessage(),
                RspEnmu.EXT_API_ERR.getMessage(),
                RspEnmu.NETWORK_EXCEPTION.getMessage(),
                RspEnmu.MONNIFY_INTERFACE_FALSE.getMessage(),
                RspEnmu.SMS_SEND_FAILD.getMessage(),
                RspEnmu.VERIFY_CODE_SEND_FAILD.getMessage())) {
            setRedis(apiName, ex, param);
            return;
        }

        String message = iSysConfigService.selectConfigByKey("ext_monitor_message");
        String substring = message.substring(2, message.length() - 2);

        if (StringUtils.containsAny(ex.toString(), substring.split("\",\""))) {
            setRedis(apiName, ex, param);
            return;
        }
    }

    public Map<String, Object> getData(String name, List<Object> args) {
        log.debug("method = {}, args = {}", name, args);

        String apiName = "";
        String param = "";

        Map<String, Object> map = new HashMap<>();

        switch (name) {
            case "aTsmsSend":
                apiName = "Africa-Talking";
                param = "message=" + args.get(1);
                break;
            case "iBSendSms":
                apiName = "Info-Bip";
                SmsData smsData = (SmsData) args.get(0);
                if (smsData != null) {
                    param = "message=" + smsData.getContent();
                }
                break;
            case "soapRequest":
                apiName = args.get(2) + "" + "[" + name + "]";
                param = args.get(0) + "";
                break;
            case "invokePayStackApi":
                apiName = args.get(0) + "";
                param = args.get(3) + "";
                break;
            case "getGeocode":
                apiName = "Google-Map-GetGeoCode";
                param = args.get(0) + "" + args.get(1);
                break;
            case "crsRequest":
                OkRequestVo okRequestVo = (OkRequestVo) args.get(0);
                apiName = okRequestVo.getApiName() + " " + "[" + name + "]";
                param = okRequestVo.getParams() + "";
                break;
            case "ruleRequest":
                apiName = args.get(2) + "" + "[" + name + "]";
                param = args.get(0) + "";
                break;
            case "monnifyAuthLogin":
                apiName = "Monnify-Auth-Login";
                break;
            case "monnifyTransactionsInitTransaction":
                apiName = "Monnify-Init-Transaction";
                param = "custNo=" + args.get(0);
                break;
            case "monnifyBankTransferInitPayment":
                apiName = "Monnify-USSD-Init-Payment";
                param = "userId=" + args.get(0);
                break;
            case "monnifyGetTransactionStatus":
                apiName = "Monnify-Query-Transaction";
                param = "transactionReference=" + args.get(0);
                break;
            case "monnifyBankTransferReservedAccounts":
                apiName = "Monnify-VA-Create";
                param = "custNo=" + args.get(0);
                break;
            case "monnifyGetBankTransferReservedAccounts":
                apiName = "Monnify-Query-VA";
                param = "custNo=" + args.get(0);
                break;
            case "monnifyGetAllTransactionsOnReservedAccount":
                apiName = "Monnify-Query-VA-All-Transactions";
                param = "custNo=" + args.get(0);
                break;
            case "callMonnifyService":
                apiName = args.get(2) + "" + "[" + name + "]";
                param = "custNo=" + args.get(0);
                break;
            case "dealPaystackForCardWithhold":
                apiName = "Paystack-Partial-Debits";
                param = "custNo=" + args.get(3);
                break;

        }
        map.put("apiName", apiName);
        map.put("param", param);

        return map;
    }

    public void setRedis(String apiName, Exception exception, String param) {

//        String content = "*`Time：`* "+ DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss")+";\\n";
//        content+="*`ApiName：`* "+apiName+";\\n";
//        content+="*`Error：`* "+ex+";\\n";
//        content+="*`Param：`* "+param;
        String ex = exception.toString();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("Time", DateUtils.dateTimeNow("yyyy-MM-dd HH:mm:ss"));
        jsonObject.put("ApiName", apiName);
        jsonObject.put("Error", ex);
        jsonObject.put("Param", param);

        String key = "ext_monitor:" + apiName + ":" + ex;

        String time = iSysConfigService.selectConfigByKey("ext_monitor_time");
        String nums = iSysConfigService.selectConfigByKey("ext_monitor_nums");

        List<Object> newList = new ArrayList<>();
        newList.add(jsonObject);
        redisCache.setCacheList(key, newList);

        List<Object> cacheList = redisCache.getCacheList(key);

        if (cacheList.size() >= Integer.parseInt(nums)) {
            JSONObject jsonObject1 = JSONObject.parseObject(cacheList.get(0).toString());

            String s = IdUtils.reqId();
            String monitorName = "monitor-group";

            MonitorLog monitorLog = new MonitorLog();
            monitorLog.setError(jsonObject1.getString("Error"));
            monitorLog.setApiName(jsonObject1.getString("ApiName"));
            monitorLog.setLogContent(cacheList.toString());
            monitorLog.setFirstTime(jsonObject1.getString("Time"));
            monitorLog.setName(monitorName);
            monitorLog.setSerialNumber(s);
            iMonitorLogService.insertMonitorLog(monitorLog);

            //发送消息
//            String content = "";
//            content += "[{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"*InterfaceError*\"}},";
//            content += "{\"type\":\"section\",\"text\":{\"type\":\"mrkdwn\",\"text\":\"";
//            content += "*`FirstTime：`* " + jsonObject1.getString("Time") + ";\\n";
//            content += "*`LogNumber：`* " + monitorLog.getId() + ";\\n";
//            content += "*`ApiName：`* " + jsonObject1.getString("ApiName") + ";\\n";
//            content += "*`Error：`* " + jsonObject1.getString("Error") + ";\\n";
//            content += "\"}}]";

            JSONObject content = new JSONObject();
            content.put("FirstTime", jsonObject1.getString("Time"));
            content.put("LogNumber", +monitorLog.getId());
            content.put("ApiName", jsonObject1.getString("ApiName"));
            content.put("Error", jsonObject1.getString("Error"));

            //String chatId = iFeishuService.sendMessageByName(monitorName,content,"InterfaceError");
            //String chatId = iSlackService.slackSendRobotMessage(content, monitorName);

            monitorLog.setContent(content.toString());
            //monitorLog.setChannel(chatId);
            iMonitorLogService.updateMonitorLog(monitorLog);

            redisCache.deleteObject(key);

            FeishuUtils.sendFeishu(monitorName, "InterfaceError", content);


            //提交monnify工单
            if (apiName.contains("monnify")) {
                if (exception instanceof BusinessException) {
                    BusinessException be = ((BusinessException) exception);
                    monnifyOrder.submitOrder(Func.isEmpty(be.getResStr()) ? be.getMessage() : be.getResStr());
                } else {
                    monnifyOrder.submitOrder(exception.getMessage());
                }
            }

        } else if (cacheList.size() == 1) {
            redisCache.expire(key, Long.parseLong(time), TimeUnit.MINUTES);
        }
    }
}
